home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / task.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-12  |  44.9 KB  |  1,754 lines  |  [TEXT/KAHL]

  1. /* Unit task execution and general task functions.
  2.    Copyright (C) 1992, 1993, 1994, 1995 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10.  
  11. static int compare_directions PROTO ((const void *a0, const void *a1));
  12.  
  13. /* This is the number of tasks to allocate initially.  More will always be
  14.    allocated as needed, so this should be a "reasonable" value. */
  15.  
  16. #ifndef INITMAXTASKS
  17. #define INITMAXTASKS 100
  18. #endif
  19.  
  20. #define can_see_actual_units(side, x, y)  \
  21.   (g_see_all() || cover((side), (x), (y)) > 0)
  22.  
  23. #define push_task(unit, task)  \
  24.   task->next = unit->plan->tasks;  \
  25.   unit->plan->tasks = task;
  26.  
  27. /* Declare all the task functions. */
  28.  
  29. #undef  DEF_TASK
  30. #define DEF_TASK(name,code,argtypes,FN)  \
  31.   static TaskOutcome FN PROTO ((Unit *unit, Task *task));
  32.  
  33. #include "task.def"
  34.  
  35. /* Array of descriptions of task types. */
  36.  
  37. TaskDefn taskdefns[] = {
  38.  
  39. #undef  DEF_TASK
  40. #define DEF_TASK(NAME,code,ARGTYPES,FN) { NAME, ARGTYPES, FN },
  41.  
  42. #include "task.def"
  43.  
  44.     { NULL, NULL, NULL }
  45. };
  46.  
  47. /* The list of available task objects. */
  48.  
  49. Task *freetasks = NULL;
  50.  
  51. /* Pointer to a buffer that task debug info goes into. */
  52.  
  53. char *taskbuf = NULL;
  54.  
  55. /* Allocate an initial collection of task objects. */
  56.  
  57. void
  58. init_tasks()
  59. {
  60.     allocate_task_block();
  61. }
  62.  
  63. /* Allocate a new block of tasks. */
  64.  
  65. void
  66. allocate_task_block()
  67. {
  68.     int i;
  69.  
  70.     freetasks = (Task *) xmalloc(INITMAXTASKS * sizeof(Task));
  71.     /* Chain the tasks together. */
  72.     for (i = 0; i < INITMAXTASKS; ++i) {
  73.     freetasks[i].next = &freetasks[i+1];
  74.     }
  75.     freetasks[INITMAXTASKS-1].next = NULL;
  76. }
  77.  
  78. /* Create and return a new task. */
  79.  
  80. Task *
  81. create_task(type)
  82. TaskType type;
  83. {
  84.     int i;
  85.     Task *task;
  86.  
  87.     /* Scarf up some more memory if we need it. */
  88.     if (freetasks == NULL) {
  89.     allocate_task_block();
  90.     }
  91.     /* Peel off a task from the free list. */
  92.     task = freetasks;
  93.     freetasks = task->next;
  94.     /* Reset its slots. */
  95.     task->type = type;
  96.     task->execnum = 0;
  97.     task->retrynum = 0;
  98.     for (i = 0; i < MAXTASKARGS; ++i) task->args[i] = 0;
  99.     task->next = NULL;
  100.     return task;
  101. }
  102.  
  103. static TaskOutcome
  104. do_none_task(unit, task)
  105. Unit *unit;
  106. Task *task;
  107. {
  108.     return TASK_IS_COMPLETE;
  109. }
  110.  
  111. static int test_for_buildable PROTO ((int x, int y));
  112.  
  113. static int tmpbuildutype;
  114.  
  115. static Unit *tmpbuilder, *tmpbuildunit;
  116.  
  117. static int
  118. test_for_buildable(x, y)
  119. int x, y;
  120. {
  121.     Unit *unit;
  122.  
  123.     for_all_stack(x, y, unit) {
  124.     if (in_play(unit)
  125.         && !fullsized(unit)
  126.         && unit->type == tmpbuildutype
  127.         && unit->side == tmpbuilder->side) {
  128.         tmpbuildunit = unit;
  129.         return TRUE;
  130.     }
  131.     }
  132.     return FALSE;
  133. }
  134.  
  135. /* The build task handles the research, tooling up, creation, and completion
  136.    for a given number of units of a given type. */
  137.  
  138. static TaskOutcome
  139. do_build_task(unit, task)
  140. Unit *unit;
  141. Task *task;
  142. {
  143.     int u = unit->type, dir, nx, ny, tp, range;
  144.     int x = unit->x, y = unit->y;
  145.     int u2 = task->args[0], run = task->args[3];
  146.     Unit *unit2 = NULL, *occ;
  147.     Side *us = unit->side;
  148.  
  149.     /* First see if we've already built all the units requested. */
  150.     if (task->args[2] >= run) {
  151.         return TASK_IS_COMPLETE;
  152.     }
  153.     /* See if our technology needs improvement in order to build this type. */
  154.     if (is_unit_type(u2)
  155.     && u_tech_to_build(u2) > 0
  156.         && us->tech[u2] < u_tech_to_build(u2)) {
  157.         if (uu_acp_to_research(u, u2) > 0) {
  158.         if (valid(check_research_action(unit, unit, u2))) {
  159.         prep_research_action(unit, unit, u2);
  160.         return TASK_PREPPED_ACTION;
  161.         } else {
  162.         /* We get three trys to research before giving up. */
  163.             return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  164.         }
  165.         } else {
  166.         /* Can't do the necessary research. */
  167.         return TASK_FAILED;
  168.         }
  169.     }
  170.     /* See if we need to toolup to work on this type. */
  171.     if (is_unit_type(u2)) {
  172.     tp = (unit->tooling ? unit->tooling[u2] : 0);
  173.     if (tp < uu_tp_to_build(u, u2)) {
  174.         if (uu_acp_to_toolup(u, u2) > 0) {
  175.         if (valid(check_toolup_action(unit, unit, u2))) {
  176.             prep_toolup_action(unit, unit, u2);
  177.             return TASK_PREPPED_ACTION;
  178.         } else {
  179.             /* We get three trys to toolup before giving up. */
  180.             return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  181.         }
  182.         } else {
  183.         /* Can't do the necessary toolup. */
  184.         return TASK_FAILED;
  185.         }
  186.     }
  187.     }
  188.     /* Check out the unit supposedly in progress. */
  189.     if (task->args[1] != 0) {
  190.     unit2 = find_unit(task->args[1]);
  191.     if (in_play(unit2) && unit2->type == u2) {
  192.         if (fullsized(unit2)) {
  193.         ++(task->args[2]);
  194.         if (task->args[2] >= run) {
  195.             return TASK_IS_COMPLETE;
  196.         }
  197.         unit2 = NULL;
  198.         } else {
  199.         /* press on */
  200.         }
  201.     } else {
  202.         unit2 = NULL;
  203.     }
  204.     }
  205.     /* Maybe search for any appropriate incomplete occupants. */
  206.     if (unit2 == NULL) {
  207.     for_all_occupants(unit, occ) {
  208.         if (in_play(occ)
  209.         && !fullsized(occ)
  210.         && occ->type == u2
  211.         && occ->side == unit->side) {
  212.         unit2 = occ;
  213.         break;
  214.         }
  215.     }
  216.     }
  217.     /* Or else search for any appropriate incomplete units in this cell. */
  218.     if (unit2 == NULL) {
  219.         for_all_stack(x, y, occ) {
  220.         if (in_play(occ)
  221.         && !fullsized(occ)
  222.         && occ->type == u2
  223.         && occ->side == unit->side) {
  224.         unit2 = occ;
  225.         break;
  226.         }
  227.         }
  228.     }
  229.     /* Or else search nearby area. */
  230.     if (is_unit_type(u2) && unit2 == NULL) {
  231.     range = uu_build_range(u, u2);
  232.     if (range > 0) {
  233.         tmpbuilder = unit;
  234.         tmpbuildutype = u2;
  235.         if (search_around(x, y, range, test_for_buildable, &nx, &ny, 1)) {
  236.             unit2 = tmpbuildunit;
  237.         }
  238.     }
  239.     }
  240.     /* No incomplete unit found, so try to create one. */
  241.     if (unit2 == NULL) {
  242.     if (valid(check_create_in_action(unit, unit, u2, unit))) {
  243.         prep_create_in_action(unit, unit, u2, unit);
  244.         return TASK_PREPPED_ACTION;
  245.     } else if (valid(check_create_at_action(unit, unit, u2, x, y, 0))) {
  246.         prep_create_at_action(unit, unit, u2, x, y, 0);
  247.         return TASK_PREPPED_ACTION;
  248.     } else {
  249.         /* Try creating in an adjacent cell. */
  250.         for_all_directions(dir) {
  251.         if (interior_point_in_dir(x, y, dir, &nx, &ny)
  252.             && valid(check_create_at_action(unit, unit, u2, nx, ny, 0))) {
  253.             prep_create_at_action(unit, unit, u2, nx, ny, 0);
  254.             return TASK_PREPPED_ACTION;
  255.         }
  256.         }
  257.         return TASK_FAILED;
  258.     }
  259.     } else {
  260.     /* Record the unit's id for use the next time around. */
  261.     task->args[1] = unit2->id;
  262.     }
  263.     /* We have an incomplete unit to work on, try to do a build action. */
  264.     if (valid(check_build_action(unit, unit, unit2))) {
  265.     prep_build_action(unit, unit, unit2);
  266.     return TASK_PREPPED_ACTION;
  267.     } else {
  268.     /* Try three times before giving up. */
  269.     return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  270.     }
  271. }
  272.  
  273. /* This is a "pure research" task, with the sole objective of increasing
  274.    technology. */
  275.  
  276. static TaskOutcome
  277. do_research_task(unit, task)
  278. Unit *unit;
  279. Task *task;
  280. {
  281.     int u = unit->type;
  282.     int u2 = task->args[0], lev = task->args[1];
  283.     Side *us = unit->side;
  284.  
  285.     /* Independents can never ever do research. */
  286.     if (us == NULL)
  287.       return TASK_FAILED;
  288.     if (us->tech[u2] > u_tech_max(u2))
  289.       return TASK_FAILED; /* actually an error */
  290.     if (us->tech[u2] >= lev)
  291.       return TASK_IS_COMPLETE;
  292.     if (uu_acp_to_research(u, u2) <= 0)
  293.       return TASK_FAILED;
  294.     if (valid(check_research_action(unit, unit, u2))) {
  295.     prep_research_action(unit, unit, u2);
  296.     return TASK_PREPPED_ACTION;
  297.     } else {
  298.     /* We get three tries to research before giving up. */
  299.     return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  300.     }
  301. }
  302.  
  303. static TaskOutcome
  304. do_capture_unit_task(unit, task)
  305. Unit *unit;
  306. Task *task;
  307. {
  308.     int u = unit->type, tx, ty, dist, movedist;
  309.     Unit *unit2;
  310.     Side *us = unit->side;
  311.  
  312.     /* This is to capture a given type/side of unit at a given place. */
  313.     /* (need to be able to say how hard to try) */
  314.     tx = task->args[0];  ty = task->args[1];
  315.     dist = distance(tx, ty, unit->x, unit->y);
  316.     switch (dist) {
  317.       case 0:
  318.     /* huh? */
  319.     return TASK_FAILED;
  320.       case 1:
  321.     if ((unit2 = unit_at(tx, ty)) != NULL) {
  322.         if (unit2->side != us /* should be "not a friendly side" */) {
  323.         if (valid(check_capture_action(unit, unit, unit2))) {
  324.             prep_capture_action(unit, unit, unit2);
  325.             return TASK_PREPPED_ACTION;
  326.         } else if (valid(check_attack_action(unit, unit, unit2, 100))) {
  327.             prep_attack_action(unit, unit, unit2, 100);
  328.             return TASK_PREPPED_ACTION;
  329.         } else {
  330.             /* We get several tries to capture before giving up. */
  331.             unit->plan->reserve = TRUE;
  332.             return (task->execnum < 5 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  333.         }
  334.         } else {
  335.         /* Our victim apparently saw the light already. */
  336.         return TASK_IS_COMPLETE;
  337.         }
  338.     } else {
  339.         /* Odd, nothing was here to capture. */
  340.         return TASK_FAILED;
  341.     }
  342.       default:
  343.         /* If on mobile transport, let it handle things. */
  344.         if (unit->transport != NULL
  345.             && mobile(unit->transport->type)
  346.         /* and the transport is not blocked */
  347.             && flip_coin()) {
  348.             return TASK_IS_INCOMPLETE;
  349.         }
  350.         /* If out of range and can move, push a task to get closer (maybe). */
  351.         if (mobile(u) && flip_coin()) {
  352.         movedist = max(1 /* attack range */, u_range(u));
  353.         if (dist > movedist + u_acp(u) /* or dist that could be covered in 1-2 turns */) {
  354.             movedist = dist - max(1, (dist - movedist) / 4);
  355.             /* We're too far away to capture directly, add a moveto task. */
  356.             push_movenear_task(unit, tx, ty, movedist);
  357.             return TASK_IS_INCOMPLETE;
  358.         }
  359.         }
  360.         return TASK_FAILED;
  361.     } 
  362. }
  363.  
  364. /* This task just attempts to do the explicitly specified action repeatedly. */
  365.  
  366. static TaskOutcome
  367. do_action_task(unit, task)
  368. Unit *unit;
  369. Task *task;
  370. {
  371.     int i;
  372.  
  373.     if (task->args[0] > 0) {
  374.     --(task->args[0]);
  375.         if (unit->act == NULL) return TASK_FAILED;
  376.         unit->act->nextaction.type = task->args[1];
  377.         for (i = 0; i < MAXACTIONARGS; ++i) {
  378.         unit->act->nextaction.args[i] = task->args[i + 2];
  379.         }
  380.         /* act on self always? */
  381.         unit->act->nextaction.actee = unit->id;
  382.     return TASK_PREPPED_ACTION;
  383.     } else {
  384.     return TASK_IS_COMPLETE;
  385.     }
  386. }
  387.  
  388. static TaskOutcome
  389. do_hit_position_task(unit, task)
  390. Unit *unit;
  391. Task *task;
  392. {
  393.     int u = unit->type, tx, ty, dist;
  394.  
  395.     /* This is to hit a given place. */
  396.     /* (ask for a number of hits?) */
  397.     tx = task->args[0];  ty = task->args[1];
  398.     dist = distance(tx, ty, unit->x, unit->y);
  399.     if (valid(check_fire_into_action(unit, unit, tx, ty, 0, -1))) {
  400.     prep_fire_into_action(unit, unit, tx, ty, 0, -1);
  401.     return TASK_PREPPED_ACTION;
  402.     } else if (mobile(u) && flip_coin()) {
  403.     /* We're too far away to shoot directly, add a moveto task. */
  404.     push_movenear_task(unit, tx, ty, max(1 /* attack range */, u_range(u)));
  405.     return TASK_IS_INCOMPLETE;
  406.     }
  407.     return TASK_FAILED;
  408. }
  409.  
  410. static TaskOutcome
  411. do_hit_unit_task(unit, task)
  412. Unit *unit;
  413. Task *task;
  414. {
  415.     int u = unit->type, tx, ty, dist, movedist, enemythere, uview, tu, ts;
  416.     Unit *unit2;
  417.     Side *us = unit->side;
  418.  
  419.     /* This is to hit a (given type/side of) unit at a given place. */
  420.     /* (should add spec for number of hits to attempt?) */
  421.     tx = task->args[0];  ty = task->args[1];
  422.     tu = task->args[2];  ts = task->args[3];
  423.     dist = distance(tx, ty, unit->x, unit->y);
  424.     if (dist <= 1 /* direct attack range */) {
  425.     for_all_stack(tx, ty, unit2) {
  426.         if (!trusted_side(us, unit2->side)
  427.             && (tu == NONUTYPE || unit2->type == tu)
  428.             /* (should check designated side to hit, if defined) */
  429.             ) {
  430.         if (valid(check_attack_action(unit, unit, unit2, 100))) {
  431.             prep_attack_action(unit, unit, unit2, 100);
  432.             return TASK_PREPPED_ACTION;
  433.         }
  434.         }
  435.     }
  436.     /* but might still be able to fire! */
  437.     return TASK_FAILED;
  438.     }
  439.     if (dist < u_range_min(u)) {
  440.     /* should move further away */
  441.     return TASK_FAILED;
  442.     }
  443.     if (dist < u_range(u)) {
  444.     if (can_see_actual_units(us, tx, ty)) {
  445.       for_all_stack(tx, ty, unit2) {
  446.         if (!trusted_side(us, unit2->side)
  447.             && (tu == NONUTYPE || unit2->type == tu)
  448.             /* (should check designated side to hit, if defined) */
  449.             ) {
  450.         if (valid(check_fire_at_action(unit, unit, unit2, -1))
  451.             && fire_can_damage(unit, unit2)) {
  452.             prep_fire_at_action(unit, unit, unit2, -1);
  453.             return TASK_PREPPED_ACTION;
  454.         }
  455.         }
  456.       }
  457.     }
  458.     return TASK_FAILED;        
  459.     }
  460.     if (can_see_actual_units(us, tx, ty)) {
  461.     enemythere = FALSE;
  462.     for_all_stack(tx, ty, unit2) {
  463.         if (!trusted_side(us, unit2->side)
  464.             && (tu == NONUTYPE || unit2->type == tu)
  465.             /* (should check designated side to hit, if defined) */
  466.             ) {
  467.             enemythere = TRUE;
  468.             break;
  469.         }
  470.     }
  471.     if (!enemythere) {
  472.         if (tu != NONUTYPE) {
  473.         return TASK_FAILED;
  474.         } else {
  475.         return TASK_IS_COMPLETE;
  476.         }
  477.     }
  478.     } else {
  479.     /* Have to assess old image or non-image. */
  480.     uview = unit_view(us, tx, ty);
  481.     if (uview != EMPTY) {
  482.         if (tu == NONUTYPE) {
  483.             /* Just keep going. */
  484.         }
  485.     } else {
  486.         /* Not clear if disappearance of target means success or failure,
  487.            but go with failure. */
  488.         return TASK_FAILED;
  489.     }
  490.     }
  491.     /* If on mobile transport, let it handle things. */
  492.     if (unit->transport != NULL
  493.         && mobile(unit->transport->type)
  494.     /* and the transport is not blocked */
  495.         && flip_coin()) {
  496.         return TASK_IS_INCOMPLETE;
  497.     }
  498.     /* If out of range and can move, push a task to get closer (maybe). */
  499.     if (mobile(u) && flip_coin()) {
  500.     movedist = max(1 /* attack range */, u_range(u));
  501.     if (dist > movedist + u_acp(u) /* or dist that could be covered in 1-2 turns */) {
  502.         movedist = dist - max(1, (dist - movedist) / 4);
  503.     }
  504.     push_movenear_task(unit, tx, ty, movedist);
  505.     return TASK_IS_INCOMPLETE;
  506.     }
  507.     return TASK_FAILED;
  508. }
  509.  
  510. /* Return true if the unit can actually damage the other unit. */
  511.  
  512. int
  513. fire_can_damage(unit, unit2)
  514. Unit *unit, *unit2;
  515. {
  516.     if (!alive(unit) || !alive(unit2)) return FALSE;
  517.     /* (should check for right kind of ammo) */
  518.     if (uu_hit(unit->type, unit2->type) <= 0) return FALSE;
  519.     /* (this is dubious - a no-damage attack could still consume acp) */
  520.     if (uu_damage(unit->type, unit2->type) <= 0) return FALSE;
  521.     /* (should check if victim hp might be under damage low bounds) */
  522.     return TRUE;
  523. }
  524.  
  525. static TaskOutcome
  526. do_movedir_task(unit, task)
  527. Unit *unit;
  528. Task *task;
  529. {
  530.     int dir, tx, ty;
  531.     Unit *unit2;
  532.  
  533.     if ((task->args[1])-- > 0) {
  534.     dir = task->args[0];
  535.     if (!point_in_dir(unit->x, unit->y, dir, &tx, &ty)) {
  536.         return TASK_FAILED;
  537.     }
  538.     if (unit_at(tx, ty)) {
  539.         for_all_stack(tx, ty, unit2) {
  540.         }
  541.         return TASK_FAILED;
  542.     } else if (valid(check_move_action(unit, unit, tx, ty, 0))) {
  543.         prep_move_action(unit, unit, tx, ty, 0);
  544.         return TASK_PREPPED_ACTION;
  545.     } else {
  546.         return TASK_FAILED;
  547.     }
  548.     } else {
  549.     return TASK_IS_COMPLETE;
  550.     }
  551. }
  552.  
  553. enum choicestate {
  554.     eitherway,
  555.     leftthenright,
  556.     rightthenleft,
  557.     leftonly,
  558.     rightonly
  559. };
  560.  
  561. static TaskOutcome
  562. do_moveto_task(unit, task)
  563. Unit *unit;
  564. Task *task;
  565. {
  566.     int u = unit->type, dist, tx, ty, nx, ny;
  567.     int dirs[NUMDIRS], numdirs, i, numdirs2;
  568.     Unit *unit2;
  569.  
  570.     /* This task is to get to a designated location somehow. */
  571.     tx = task->args[0];  ty = task->args[1];
  572.     dist = distance(tx, ty, unit->x, unit->y);
  573.     if (dist <= task->args[2]) {
  574.     return TASK_IS_COMPLETE;
  575.     }
  576.     switch (dist) {
  577.       case 0:
  578.     /* We're there already, nothing more to do. */
  579.     return TASK_IS_COMPLETE;
  580.       case 1:
  581.     /* Adjacent cell, do a single move. */
  582.     /* (similar to multi-move case, merge code?) */
  583.     if (unit_at(tx, ty)) {
  584.         for_all_stack(tx, ty, unit2) {
  585.         if (can_occupy(unit, unit2)) {
  586.             if (valid(check_enter_action(unit, unit, unit2))) {
  587.             prep_enter_action(unit, unit, unit2);
  588.             return TASK_PREPPED_ACTION;
  589.             } else {
  590.             continue;
  591.             }
  592.         } else if (!trusted_side(unit->side, unit2->side)) {
  593.             if (valid(check_attack_action(unit, unit, unit2, 100))) {
  594.             prep_attack_action(unit, unit, unit2, 100);
  595.             return TASK_PREPPED_ACTION;
  596.             } else {
  597.             continue;
  598.             }
  599.         }
  600.         }
  601.         return TASK_FAILED;
  602.     }
  603.     if (valid(check_move_action(unit, unit, tx, ty, unit->z))) {
  604.         /* Moving into an empty cell. */
  605.         prep_move_action(unit, unit, tx, ty, unit->z);
  606.         return TASK_PREPPED_ACTION;
  607.     } else {
  608.         return TASK_FAILED;
  609.     }
  610.     break;
  611.       default:
  612.     /* Still some distance away, pick a way to go. */
  613.         /* If on mobile transport, let it handle things. */
  614.         if (unit->transport != NULL
  615.             && mobile(unit->transport->type)
  616.             /* and the transport is not blocked */
  617.             && flip_coin()) {
  618.             unit->plan->reserve = TRUE;
  619.             return TASK_IS_INCOMPLETE;
  620.         }
  621.     numdirs = choose_move_dirs(unit, tx, ty, TRUE,
  622.                    plausible_move_dir, sort_directions, dirs);
  623.     for (i = 0; i < numdirs; ++i) {
  624.         point_in_dir(unit->x, unit->y, dirs[i], &nx, &ny);
  625.         for_all_stack(nx, ny, unit2) {
  626.         if (can_occupy(unit, unit2)) {
  627.             if (valid(check_enter_action(unit, unit, unit2))) {
  628.             prep_enter_action(unit, unit, unit2);
  629.             /* We (probably) made forward progress, so reopen choice of dirs. */
  630.             task->args[3] = eitherway;
  631.             return TASK_PREPPED_ACTION;
  632.             } else {
  633.             continue;
  634.             }
  635.         } else if (!trusted_side(unit->side, unit2->side)) {
  636.             if (unit->occupant) {
  637.                 /* More important to find a way through. */
  638.                 continue;
  639.             } else {
  640.                 /* This will encourage some re-evaluation. */
  641.                 return TASK_FAILED;
  642.             }
  643. #if 0 /* the following is rarely a good idea */
  644.             if (valid(check_attack_action(unit, unit, unit2, 100))) {
  645.             prep_attack_action(unit, unit, unit2, 100);
  646.             /* We (probably) made forward progress, so reopen choice of dirs. */
  647.             task->args[3] = eitherway;
  648.             return TASK_PREPPED_ACTION;
  649.             } else {
  650.             continue;
  651.             }
  652. #endif
  653.         }
  654.         }
  655.         if (valid(check_move_action(unit, unit, nx, ny, unit->z))) {
  656.         prep_move_action(unit, unit, nx, ny, unit->z);
  657.         /* We (probably) made forward progress, so reopen choice of dirs. */
  658.         task->args[3] = eitherway;
  659.         return TASK_PREPPED_ACTION;
  660.         }
  661.     }
  662.     /* Get both right and left non-decreasing dirs. */
  663.     numdirs  = choose_move_dirs(unit, tx, ty, TRUE, NULL, NULL, dirs);
  664.     numdirs2 = choose_move_dirs(unit, tx, ty, FALSE, NULL, NULL, dirs);
  665.     for (i = numdirs; i < numdirs2; ++i) {
  666.       if (plausible_move_dir(unit, dirs[i])) {
  667.         switch (task->args[3]) {
  668.           case eitherway:
  669.         if (i == numdirs) task->args[3] = leftonly /* leftthenright */;
  670.             if (i == numdirs+1) task->args[3] = rightonly /* rightthenleft */;
  671.         break;
  672.           case leftthenright:
  673.         if (i == numdirs) task->args[3] = rightonly;
  674.             if (i == numdirs+1) task->args[3] = rightonly;
  675.             continue;
  676.         break;
  677.           case rightthenleft:
  678.             if (i == numdirs+1) task->args[3] = leftonly;
  679.             continue;
  680.         break;
  681.           case leftonly:
  682.             if (i == numdirs+1) continue;
  683.         break;
  684.           case rightonly:
  685.             if (i == numdirs) continue;
  686.         break;
  687.         }
  688.       } else {
  689.         switch (task->args[3]) {
  690.           case eitherway:
  691.             if (i == numdirs) task->args[3] = rightonly;
  692.                 if (i == numdirs+1) task->args[3] = leftonly;
  693.                 continue;
  694.         break;
  695.           case leftthenright:
  696.             if (i == numdirs) task->args[3] = rightonly;
  697.                 if (i == numdirs+1) task->args[3] = rightonly;
  698.                 continue;
  699.         break;
  700.           case rightthenleft:
  701.                 if (i == numdirs+1) task->args[3] = leftonly;
  702.                 continue;
  703.         break;
  704.           case leftonly:
  705.             if (i == numdirs) return TASK_FAILED;
  706.             if (i == numdirs+1) continue;
  707.         break;
  708.           case rightonly:
  709.             if (i == numdirs) continue;
  710.             if (i == numdirs+1) return TASK_FAILED;
  711.         break;
  712.         }
  713.       }
  714.         point_in_dir(unit->x, unit->y, dirs[i], &nx, &ny);
  715.         for_all_stack(nx, ny, unit2) {
  716.         if (can_occupy(unit, unit2)) {
  717.             if (valid(check_enter_action(unit, unit, unit2))) {
  718.             prep_enter_action(unit, unit, unit2);
  719.             return TASK_PREPPED_ACTION;
  720.             } else {
  721.             continue;
  722.             }
  723.         } else if (!trusted_side(unit->side, unit2->side)) {
  724.             if (unit->occupant) {
  725.                 /* More important to find a way through. */
  726.                 continue;
  727.             } else {
  728.                 /* This will encourage some re-evaluation. */
  729.                 return TASK_FAILED;
  730.             }
  731. #if 0 /* the following is rarely a good idea */
  732.             if (valid(check_attack_action(unit, unit, unit2, 100))) {
  733.             prep_attack_action(unit, unit, unit2, 100);
  734.             return TASK_PREPPED_ACTION;
  735.             } else {
  736.             continue;
  737.             }
  738. #endif
  739.         }
  740.         }
  741.         if (valid(check_move_action(unit, unit, nx, ny, unit->z))) {
  742.         prep_move_action(unit, unit, nx, ny, unit->z);
  743.         return TASK_PREPPED_ACTION;
  744.         }
  745.     }
  746.     }
  747.     return TASK_FAILED;
  748. }
  749.  
  750. static TaskOutcome
  751. do_occupy_task(unit, task)
  752. Unit *unit;
  753. Task *task;
  754. {
  755.     Unit *transport = find_unit(task->args[0]);
  756.  
  757.     if (!in_play(transport)) return TASK_FAILED;
  758.     if (unit->transport == transport) {
  759.     return TASK_IS_COMPLETE;
  760.     }
  761.     return TASK_FAILED;
  762. }
  763.  
  764. /* Wait around for a particular unit.  Give up if the unit is not forthcoming. */
  765.  
  766. static TaskOutcome
  767. do_pickup_task(unit, task)
  768. Unit *unit;
  769. Task *task;
  770. {
  771.     Unit *occupant = find_unit(task->args[0]);
  772.  
  773.     if (!in_play(occupant)) return TASK_FAILED;
  774.     wake_unit(occupant, FALSE, 0, NULL);
  775.     if (occupant->transport == unit) {
  776.     return TASK_IS_COMPLETE;
  777.     } else if (task->execnum > 10) {
  778.     /* Waiting around isn't working for us, give up.  If the
  779.        prospective occupant still needs us, we'll get another
  780.        call. */
  781.     return TASK_FAILED;
  782.     } else {
  783.     if (valid(check_enter_action(occupant, occupant, unit))) {
  784.         prep_enter_action(occupant, occupant, unit);
  785.         return TASK_PREPPED_ACTION;
  786.     } else if (valid(check_enter_action(unit, occupant, unit))) {
  787.         prep_enter_action(unit, occupant, unit);
  788.         return TASK_PREPPED_ACTION;
  789.     } else {
  790.         return (task->execnum < 5 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  791.     }
  792.     }
  793. }
  794.  
  795. Unit *
  796. repair_here(x, y)
  797. int x, y;
  798. {
  799.     Unit *unit;
  800.  
  801.     for_all_stack(x, y, unit) {
  802.     /* what about allies? */
  803.     if (unit->side == tmpside && can_carry(unit, tmpunit)) {
  804.         /* this should be controlled by doctrine? */
  805.         /* shouldn't wake up, should get a new task to "wait up"
  806.            or even approach if possible */
  807.     /*    wake_unit(unit, FALSE, WAKEOWNER, NULL);  */
  808.         return unit;
  809.     }
  810.     /* should look at occupants in stack too */
  811.     }
  812.     return NULL;
  813. }
  814.  
  815. int
  816. repair_test(x, y)
  817. int x, y;
  818. {
  819.     return (repair_here(x, y) != NULL);
  820. }
  821.  
  822. static TaskOutcome
  823. do_repair_task(unit, task)
  824. Unit *unit;
  825. Task *task;
  826. {
  827.     int x, y, u = unit->type, m, range = area.maxdim;
  828.     int ux = unit->x, uy = unit->y;
  829.     Unit *unit2;
  830.  
  831.     for_all_material_types(m) {
  832.     if (um_consumption_per_move(u, m) > 0) {
  833.         range = min(range, unit->supply[m] / um_consumption_per_move(u, m));
  834.     }
  835.     }
  836.     tmpside = unit->side;
  837.     tmpunit = unit;
  838.     if (unit->hp == u_hp(u)) {  /* what if unit is multi-part? */
  839.         return TASK_IS_COMPLETE;
  840.     } else if (unit->transport != NULL) {
  841.     set_unit_reserve(unit->side, unit, TRUE, FALSE);
  842.         return TASK_IS_INCOMPLETE;
  843.     } else if ((unit2 = repair_here(ux, uy)) != NULL
  844.         && unit2 != unit->transport) {    
  845.         prep_enter_action(unit, unit, unit2);
  846.     return TASK_PREPPED_ACTION;
  847.     } else if (search_around(ux, uy, range, repair_test, &x, &y, 1)) {
  848.         /* (should collect actual unit and chase it directly) */
  849.     push_moveto_task(unit, x, y);
  850.     return TASK_IS_INCOMPLETE;
  851.     } else {
  852.         /* (should be able to signal interface usefully somehow) */
  853.     return TASK_FAILED;
  854.     }
  855. }
  856.  
  857. int *lowm = NULL, numlow; 
  858.  
  859. Unit *
  860. aux_resupply_here(unit)
  861. Unit *unit;
  862. {
  863.     int i, enough = TRUE;
  864.     Unit *occ;
  865.  
  866.     /* what about allies? */
  867.     if (unit->side == tmpside
  868.     && can_carry(unit, tmpunit)) {
  869.     for (i = 0; i < numlow; ++i) {
  870.         if (unit->supply[lowm[i]] == 0) enough = FALSE;
  871.     }
  872.     /* should test that unit has desired supply too... */
  873.     /* this should be controlled by doctrine? */
  874.     /* shouldn't wake up, should get a new task to "wait up"
  875.        or even approach if possible */
  876.     /*    wake_unit(unit, FALSE, WAKEOWNER, NULL);  */
  877.     if (enough) return unit;
  878.     }
  879.     for_all_occupants(unit, occ) {
  880.     if (aux_resupply_here(occ)) {
  881.         return occ;
  882.     }
  883.     }
  884.     return NULL;
  885. }
  886.  
  887. Unit *
  888. resupply_here(x, y)
  889. int x, y;
  890. {
  891.     Unit *unit, *resupplier;
  892.  
  893.     for_all_stack(x, y, unit) {
  894.         resupplier = aux_resupply_here(unit);
  895.         if (resupplier) return resupplier;
  896.     }
  897.     return NULL;
  898. }
  899.  
  900. int
  901. resupply_test(x, y)
  902. int x, y;
  903. {
  904.     return (resupply_here(x, y) != NULL);
  905. }
  906.  
  907. /* Replenish our supplies, using one of several strategies, which as usual
  908.    depends on the game, unit, terrain, etc.  Strategies include 1) wait for
  909.    supply line or own production to replenish, 2) move to productive terrain
  910.    and then wait, 3) move within range of a supplier, and 4) request a supplier
  911.    to approach. */
  912.  
  913. /* (should see if production actions would resupply, prep those actions) */
  914.  
  915. static TaskOutcome
  916. do_resupply_task(unit, task)
  917. Unit *unit;
  918. Task *task;
  919. {
  920.     int x, y, u = unit->type, m, range = area.maxdim;
  921.     int ux = unit->x, uy = unit->y;
  922.     Unit *unit2;
  923.  
  924.     tmpside = unit->side;
  925.     tmpunit = unit;
  926.     if (lowm == NULL) lowm = (int *) xmalloc(nummtypes * sizeof(int));
  927.     numlow = 0;
  928.     for_all_material_types(m) {
  929.         if (unit->supply[m] < um_storage_x(u, m)) {
  930.             lowm[numlow++] = m;
  931.             /* (doesn't account for shared hold) */
  932.         }
  933.     if (um_consumption_per_move(u, m) > 0) {
  934.         range = min(range, unit->supply[m] / um_consumption_per_move(u, m));
  935.     }
  936.     }
  937.     /* We're all full up, must be OK. */
  938.     if (numlow == 0) {
  939.         return TASK_IS_COMPLETE;
  940.     } else if (can_auto_resupply_self(unit, lowm, numlow)) {
  941.     set_unit_reserve(unit->side, unit, TRUE, FALSE);
  942.         return (probability(10) ? TASK_FAILED : TASK_IS_INCOMPLETE);
  943.     } else if (unit->transport != NULL) {
  944.         /* (could attempt to resupply via direct action) */
  945.     set_unit_reserve(unit->side, unit, TRUE, FALSE);
  946.         return (probability(10) ? TASK_FAILED : TASK_IS_INCOMPLETE);
  947.     } else if ((unit2 = resupply_here(ux, uy)) != NULL
  948.         && unit2 != unit->transport) {    
  949.         prep_enter_action(unit, unit, unit2);
  950.     return TASK_PREPPED_ACTION;
  951.     } else if (search_around(ux, uy, range, resupply_test, &x, &y, 1)) {
  952.         /* (should collect actual unit and chase it directly) */
  953.         /* (only need to get within outlength of needed supplies) */
  954.     push_moveto_task(unit, x, y);
  955.     return TASK_IS_INCOMPLETE;
  956.     } else {
  957.     /* Failure - sometimes just sit, but usually try something else. */
  958.     if (probability(10))
  959.       set_unit_reserve(unit->side, unit, TRUE, FALSE);
  960.         /* (should be able to signal interface usefully somehow) */
  961.     return TASK_FAILED;
  962.     }
  963. }
  964.  
  965. /* Return true if our own automatic material production is *greater*
  966.    than our consumption. */
  967.  
  968. int
  969. can_auto_resupply_self(unit, materials, numtypes)
  970. Unit *unit;
  971. int *materials, numtypes;
  972. {
  973.     int u = unit->type, i, m, rslt = TRUE, t = terrain_at(unit->x, unit->y);
  974.  
  975.     for (i = 0; i < numtypes; ++i) {
  976.         m = materials[i];
  977.     if (um_base_production(u, m) * ut_productivity(u, t) <= um_base_consumption(u, m))
  978.       rslt = FALSE;
  979.     }
  980.     return rslt;
  981. }
  982.  
  983. static TaskOutcome
  984. do_sentry_task(unit, task)
  985. Unit *unit;
  986. Task *task;
  987. {
  988.     if (task->args[0] > 0) {
  989.     unit->plan->reserve = TRUE;
  990.     --(task->args[0]);
  991.     return TASK_IS_INCOMPLETE;
  992.     } else {
  993.     /* Unit won't necessarily wake up, may just replan and
  994.        continue sleeping. */
  995.     return TASK_IS_COMPLETE;
  996.     }
  997. }
  998.  
  999. /* This is the main routine for a unit to execute a task.  It basically
  1000.    consists of a dispatch to the execution code for each task type, and
  1001.    handling for a task's several possible outcomes.  Note that a task
  1002.    does *not* directly invoke any actions; instead it will schedule
  1003.    ("prep") an action, which will be executed later by execute_action.
  1004.    Therefore, it is possible for a task to succeed but the action to
  1005.    fail, although each task type's code tries to reduce the chances
  1006.    of this happening (not possible to prevent entirely - unit may
  1007.    become damaged and unable to do perform an action after the task
  1008.    had decided on that action). */
  1009.  
  1010. TaskOutcome
  1011. execute_task(unit)
  1012. Unit *unit;
  1013. {
  1014.     Plan *plan = unit->plan;
  1015.     TaskOutcome rslt;
  1016.     Task *task;
  1017.  
  1018.     /* This should never happen. */
  1019.     if (unit->plan == NULL) run_error("???");
  1020.     task = plan->tasks;
  1021.     rslt = execute_task_aux(unit, task);
  1022.     DMprintf("%s did task %s: ", unit_desig(unit), task_desig(task));
  1023.     /* Now look at what happened with task execution. */
  1024.     switch (rslt) {
  1025.       case TASK_UNKNOWN:
  1026.     DMprintf("unknown outcome???");
  1027.     break;
  1028.       case TASK_FAILED:
  1029.         ++task->retrynum;
  1030.     DMprintf("failed try %d, ", task->retrynum);
  1031.     if (probability(20) || task->retrynum > 5) {
  1032.         pop_task(plan);
  1033.         DMprintf("removed it");
  1034.         /* We might be buzzing, so maybe go into reserve. */
  1035.         if (probability(20)) {
  1036.             plan->reserve = TRUE;
  1037.             DMprintf(" and went into reserve");
  1038.         }
  1039.     } else {
  1040.         DMprintf("will retry");
  1041.     }
  1042.     break;
  1043.       case TASK_IS_INCOMPLETE:
  1044.     /* Leave the task alone. */
  1045.     DMprintf("incomplete");
  1046.     break;
  1047.       case TASK_PREPPED_ACTION:
  1048.     /* Mention the action prepared to execute. */
  1049.     DMprintf("prepped action %s", action_desig(&(unit->act->nextaction)));
  1050.     break;
  1051.       case TASK_IS_COMPLETE:
  1052.     DMprintf("completed after %d executions", task->execnum);
  1053.     pop_task(plan);
  1054.     break;
  1055.       default:
  1056.     break;
  1057.     }
  1058.     DMprintf("\n");
  1059.     /* Give AIs a chance to decide what to do with the result of a task. */
  1060.     if (unit->side != NULL && side_has_ai(unit->side)) {
  1061.         ai_react_to_task_result(unit->side, unit, task, rslt);
  1062.     }
  1063.     return rslt;
  1064. }
  1065.  
  1066. /* Perform a single given task. */
  1067.  
  1068. TaskOutcome
  1069. execute_task_aux(unit, task)
  1070. Unit *unit;
  1071. Task *task;
  1072. {
  1073.     if (!alive(unit) || task == NULL) return 0;
  1074.     DMprintf("%s doing task %s\n", unit_desig(unit), task_desig(task));
  1075.     /* Count this execution. */
  1076.     ++task->execnum;
  1077.     /* (should use function pointer table...) */
  1078.     switch (task->type) {
  1079.       case TASK_NONE:
  1080.     /* This is a no-op, useful as a placeholder.  Always "succeeds". */
  1081.     return TASK_IS_COMPLETE;
  1082.       case TASK_BUILD:
  1083.     return do_build_task(unit, task);
  1084.       case TASK_RESEARCH:
  1085.     return do_research_task(unit, task);
  1086.       case TASK_CAPTURE_UNIT:
  1087.     return do_capture_unit_task(unit, task);
  1088.       case TASK_DO_ACTION:
  1089.     return do_action_task(unit, task);
  1090.       case TASK_HIT_POSITION:
  1091.     return do_hit_position_task(unit, task);
  1092.       case TASK_HIT_UNIT:
  1093.     return do_hit_unit_task(unit, task);
  1094.       case TASK_MOVEDIR:
  1095.     return do_movedir_task(unit, task);
  1096.       case TASK_MOVETO:
  1097.     return do_moveto_task(unit, task);
  1098.       case TASK_OCCUPY:
  1099.         return do_occupy_task(unit, task);
  1100.       case TASK_PICKUP:
  1101.         return do_pickup_task(unit, task);
  1102.       case TASK_REPAIR:
  1103.         return do_repair_task(unit, task);
  1104.       case TASK_RESUPPLY:
  1105.         return do_resupply_task(unit, task);
  1106.       case TASK_SENTRY:
  1107.         return do_sentry_task(unit, task);
  1108.       default:
  1109.     /* This is bad, but not necessarily a reason to die instantly. */
  1110.     run_warning("Unknown task type %d", task->type);
  1111.         return TASK_FAILED;
  1112.     }
  1113. }
  1114.  
  1115. /* This weird-looking routine computes next directions for moving to a
  1116.    given spot.  The number of directions ranges from 1 to 4, depending
  1117.    on whether there is a straight-line path to the dest, and whether we are
  1118.    required to take a direct path or are allowed to move in dirs that don't
  1119.    the unit any closer (we never increase our distance though).
  1120.    Some trickinesses:  if area wraps, must resolve ambiguity about
  1121.    getting to the same place going either direction (we pick shortest). */
  1122.  
  1123. int
  1124. choose_move_dirs(unit, tx, ty, shortest, dirtest, dirsort, dirs)
  1125. Unit *unit;
  1126. int tx, ty, shortest, *dirs;
  1127. int (*dirtest) PROTO ((Unit *, int));
  1128. void (*dirsort) PROTO ((Unit *, int *, int));
  1129. {
  1130.     int dx, dxa, dy, dist, d1, d2, d3, d4, axis = -1, hextant = -1;
  1131.     int numdirs = 0, shortestnumdirs;
  1132.  
  1133.     dist = distance(unit->x, unit->y, tx, ty);
  1134.     dx = tx - unit->x;  dy = ty - unit->y;
  1135.  
  1136.     if (area.xwrap) {
  1137.     dxa = (tx + area.width) - unit->x;
  1138.     if (ABS(dx) > ABS(dxa)) dx = dxa;
  1139.     dxa = (tx - area.width) - unit->x;
  1140.     if (ABS(dx) > ABS(dxa)) dx = dxa;
  1141.     }
  1142.     if (dx == 0 && dy == 0) {
  1143.     return -1;
  1144.     }
  1145.     axis = hextant = -1;
  1146.     if (dx == 0) {
  1147.     axis = (dy > 0 ? NORTHEAST : SOUTHWEST);
  1148.     } else if (dy == 0) {
  1149.     axis = (dx > 0 ? EAST : WEST);
  1150.     } else if (dx == (0 - dy)) {
  1151.     axis = (dy > 0 ? NORTHWEST : SOUTHEAST);
  1152.     } else if (dx > 0) {
  1153.     hextant = (dy > 0 ? EAST :
  1154.            (ABS(dx) > ABS(dy) ? SOUTHEAST : SOUTHWEST));
  1155.     } else {
  1156.     hextant = (dy < 0 ? WEST :
  1157.            (ABS(dx) > ABS(dy) ? NORTHWEST : NORTHEAST));
  1158.     }
  1159.     if (axis >= 0) {
  1160.     d1 = d2 = axis;
  1161.     if (dirtest == NULL || (*dirtest)(unit, d1)) {
  1162.         dirs[numdirs++] = d1;
  1163.     }
  1164.     }
  1165.     if (hextant >= 0) {
  1166.     d1 = left_dir(hextant);
  1167.     d2 = hextant;
  1168.     if (dirtest == NULL || (*dirtest)(unit, d1)) {
  1169.         dirs[numdirs++] = d1;
  1170.     }
  1171.     if (dirtest == NULL || (*dirtest)(unit, d2)) {
  1172.         dirs[numdirs++] = d2;
  1173.     }
  1174.     }
  1175.     /* Check on other properties of the two choices. */
  1176.     if (numdirs > 1 && dirsort != NULL) {
  1177.         (*dirsort)(unit, dirs, numdirs);
  1178.     }
  1179.     if (dist > 1 && !shortest) {
  1180.     shortestnumdirs = numdirs;
  1181.         d3 = left_dir(d1);
  1182.         d4 = right_dir(d2);
  1183.     if (dirtest == NULL || (*dirtest)(unit, d3)) {
  1184.         dirs[numdirs++] = d3;
  1185.     }
  1186.     if (dirtest == NULL || (*dirtest)(unit, d4)) {
  1187.         dirs[numdirs++] = d4;
  1188.     }
  1189.     if (numdirs > shortestnumdirs + 1 && dirsort != NULL) {
  1190.         (*dirsort)(unit, dirs + shortestnumdirs, numdirs - shortestnumdirs);
  1191.     }
  1192.     }
  1193.     return numdirs;
  1194. }
  1195.  
  1196. /* A heuristic test for whether the given direction is a good one
  1197.    to move in. */
  1198.  
  1199. int
  1200. plausible_move_dir(unit, dir)
  1201. Unit *unit;
  1202. int dir;
  1203. {
  1204.     int u = unit->type, ux = unit->x, uy = unit->y, nx, ny, t, c;
  1205.  
  1206.     point_in_dir(ux, uy, dir, &nx, &ny);
  1207.     if (unit_at(nx, ny)) return TRUE;
  1208.     t = terrain_at(nx, ny);
  1209.     if ((ut_vanishes_on(u, t)
  1210.          || ut_wrecks_on(u, t))
  1211.         && !can_move_via_conn(unit, nx, ny)) return FALSE;
  1212.     if (ut_mp_to_enter(u, t) <= u_acp(u)) return TRUE;
  1213.     if (numconntypes > 0) {
  1214.     /* Try each connection type to see if it works. */
  1215.     for_all_terrain_types(c) {
  1216.         if (t_is_connection(c)
  1217.         && aux_terrain_defined(c)
  1218.         && connection_at(ux, uy, dir, c)) {
  1219.         if ((ut_mp_to_enter(u, c)
  1220.              + ut_mp_to_traverse(u, c)
  1221.              + ut_mp_to_leave(u, c)) <= u_acp(u)) return TRUE;
  1222.         }
  1223.     }
  1224.     }
  1225.     return FALSE;
  1226. }
  1227.  
  1228. /* This compares the desirability of two different directions.  This is
  1229.    somewhat tricky, because it should return < 0 if i0 designates a BETTER
  1230.    direction than i1. */
  1231.  
  1232. int xs[NUMDIRS], ys[NUMDIRS], terrs[NUMDIRS];
  1233.  
  1234. static int
  1235. compare_directions(a0, a1)
  1236. CONST void *a0, *a1;
  1237. {
  1238.     int i0, i1;
  1239.     int u = tmputype, t0, t1;
  1240.     int ux = tmpunit->x, uy = tmpunit->y, u2 = NONUTYPE;
  1241.     int cost0 = 0, cost1 = 0, s, ps0, ps1, surr0, surr1, rslt;
  1242.     extern int *any_people_surrenders;
  1243.  
  1244.     i0 = *((int *) a0);  i1 = *((int *) a1);
  1245.     t0 = terrs[i0];  t1 = terrs[i1];
  1246.     if (tmpunit->transport) u2 = tmpunit->transport->type;
  1247.     /* Check the overall movement cost of each direction. */
  1248.     cost0 = total_move_cost(u, u2, ux, uy, 0, xs[i0], ys[i0], 0);
  1249.     cost1 = total_move_cost(u, u2, ux, uy, 0, xs[i1], ys[i1], 0);
  1250.     if (cost0 != cost1) {
  1251.     return cost0 - cost1;
  1252.     }
  1253.     if (1 /* not in supply */) {
  1254.     if ((rslt = ut_productivity(u, t1) - ut_productivity(u, t0)) != 0) {
  1255.         return rslt;
  1256.     }
  1257.     }
  1258.     if ((rslt = ut_mp_to_leave(u, t1) - ut_mp_to_leave(u, t0)) != 0) {
  1259.     return rslt;
  1260.     }
  1261.     /* Chooser the safer terrain. */
  1262.     if ((rslt = ut_accident_hit(u, t1) - ut_accident_hit(u, t0)) != 0) {
  1263.     return rslt;
  1264.     }
  1265.     /* Choose the better-concealing terrain. */
  1266.     /* (should only do if limited visibility) */
  1267.     if ((rslt = ut_visibility(u, t1) - ut_visibility(u, t0)) != 0) {
  1268.     return rslt;
  1269.     }
  1270.     /* Prefer to go over cells that we can change to our side. */
  1271.     if (any_people_surrenders != NULL && any_people_surrenders[u]) {
  1272.         s = side_number(tmpunit->side);
  1273.         ps0 = people_side_at(xs[i0], ys[i0]);
  1274.         ps1 = people_side_at(xs[i1], ys[i1]);
  1275.         surr0 = ut_people_surrender(u, t0)
  1276.       * ((ps0 != NOBODY && s != ps0) ? 1 : 0);
  1277.         surr1 = ut_people_surrender(u, t1)
  1278.       * ((ps1 != NOBODY && s != ps1) ? 1 : 0);
  1279.         if (surr0 != surr1) {
  1280.         return surr1 - surr0;
  1281.         }
  1282.     }
  1283.     return 0;
  1284. }
  1285.  
  1286. void
  1287. sort_directions(unit, dirs, numdirs)
  1288. Unit *unit;
  1289. int *dirs, numdirs;
  1290. {
  1291.     int i, u = unit->type, tmp, i0 = 0, i1 = 1, compar;
  1292.  
  1293.     for (i = 0; i < numdirs; ++i) { 
  1294.     point_in_dir(unit->x, unit->y, dirs[i], &(xs[i]), &(ys[i]));
  1295.     terrs[i] = terrain_at(xs[i], ys[i]);
  1296.     }
  1297.     tmpunit = unit;
  1298.     tmputype = unit->type;
  1299.     if (numdirs == 2) {
  1300.     compar = compare_directions(&i0, &i1);
  1301.         if (compar > 0 || (compar == 0 && flip_coin())) {
  1302.             tmp = dirs[0];  dirs[0] = dirs[1];  dirs[1] = tmp;
  1303.         }
  1304.     } else if (numdirs > 2) {
  1305.         qsort(dirs, numdirs, sizeof(int), compare_directions);
  1306.     if (compare_directions(&i0, &i1) == 0 && flip_coin()) {
  1307.         tmp = dirs[0];  dirs[0] = dirs[1];  dirs[1] = tmp;
  1308.     }
  1309.     }
  1310. }
  1311.  
  1312. /* Put the given task back onto the list of free tasks. */
  1313.  
  1314. void 
  1315. free_task(task)
  1316. Task *task;
  1317. {
  1318.     task->next = freetasks;
  1319.     freetasks = task;
  1320. }
  1321.  
  1322. /* Make the given unit be able to execute its plan. */
  1323.  
  1324. void
  1325. be_active(unit)
  1326. Unit *unit;
  1327. {
  1328.     if (unit->plan == NULL) return;
  1329.     /* Shouldn't be asleep any longer. */
  1330.     unit->plan->asleep = FALSE;
  1331.     /* We're not in reserve. */
  1332.     unit->plan->reserve = FALSE;
  1333.     /* Obviously we're no longer waiting to be told what to do. */
  1334.     unit->plan->waitingfortasks = FALSE;
  1335. }
  1336.  
  1337. /* Order a unit to sit quietly for some number of turns. */
  1338.  
  1339. Task *
  1340. create_sentry_task(n)
  1341. int n;
  1342. {
  1343.     Task *task = create_task(TASK_SENTRY);
  1344.  
  1345.     task->args[0] = n;
  1346.     return task;
  1347. }
  1348.  
  1349. void
  1350. push_sentry_task(unit, n)
  1351. Unit *unit;
  1352. int n;
  1353. {
  1354.     Task *task;
  1355.  
  1356.     if (!tasked_unit_valid(unit, "sentry"))
  1357.       return;
  1358.     task = create_sentry_task(n);
  1359.     push_task(unit, task);
  1360.     /* Obviously we're no longer waiting to be told what to do. */
  1361.     unit->plan->waitingfortasks = FALSE;
  1362.     update_unit_display(unit->side, unit, FALSE);
  1363. }
  1364.  
  1365. Task *
  1366. create_moveto_task(x, y)
  1367. int x, y;
  1368. {
  1369.     Task *task = create_task(TASK_MOVETO);
  1370.  
  1371.     task->args[0] = x;  task->args[1] = y;
  1372.     return task;
  1373. }
  1374.  
  1375. void
  1376. order_sentry(unit, n)
  1377. Unit *unit;
  1378. int n;
  1379. {
  1380.     if (!tasked_unit_valid(unit, "sentry"))
  1381.       return;
  1382.     clear_task_agenda(unit->plan);
  1383.     unit->plan->tasks = create_sentry_task(n);
  1384.     /* We're no longer waiting to be told what to do. */
  1385.     unit->plan->waitingfortasks = FALSE;
  1386.     update_unit_display(unit->side, unit, FALSE);
  1387. }
  1388.  
  1389. void
  1390. push_moveto_task(unit, x, y)
  1391. Unit *unit;
  1392. int x, y;
  1393. {
  1394.     Task *task;
  1395.  
  1396.     if (!tasked_unit_valid(unit, "move"))
  1397.       return;
  1398.     task = create_moveto_task(x, y);
  1399.     push_task(unit, task);
  1400.     /* Obviously we're no longer waiting to be told what to do. */
  1401.     unit->plan->waitingfortasks = FALSE;
  1402.     update_unit_display(unit->side, unit, FALSE);
  1403. }
  1404.  
  1405. /* Give the unit a task to move to a given place, erasing every other task. */
  1406.  
  1407. void
  1408. order_moveto(unit, x, y)
  1409. Unit *unit;
  1410. int x, y;
  1411. {
  1412.     if (!tasked_unit_valid(unit, "move"))
  1413.       return;
  1414.     if (!in_area(x, y)) {
  1415.         run_warning("Trying to move %s to %d,%d", unit_desig(unit), x, y);
  1416.         return;
  1417.     }
  1418.     clear_task_agenda(unit->plan);
  1419.     unit->plan->tasks = create_moveto_task(x, y);
  1420.     be_active(unit);
  1421.     update_unit_display(unit->side, unit, FALSE);
  1422. }
  1423.  
  1424. void
  1425. set_moveto_task(unit, x, y)
  1426. Unit *unit;
  1427. int x, y;
  1428. {
  1429.     if (!tasked_unit_valid(unit, "move"))
  1430.       return;
  1431.     if (!in_area(x, y)) {
  1432.         run_warning("Trying to move %s to %d,%d", unit_desig(unit), x, y);
  1433.         return;
  1434.     }
  1435.     clear_task_agenda(unit->plan);
  1436.     unit->plan->tasks = create_moveto_task(x, y);
  1437.     be_active(unit);
  1438.     update_unit_display(unit->side, unit, FALSE);
  1439. }
  1440.  
  1441. Task *
  1442. create_movenear_task(x, y, dist)
  1443. int x, y, dist;
  1444. {
  1445.     Task *task = create_task(TASK_MOVETO);
  1446.  
  1447.     task->args[0] = x;  task->args[1] = y;
  1448.     task->args[2] = dist;
  1449.     return task;
  1450. }
  1451.  
  1452. void
  1453. set_movenear_task(unit, x, y, dist)
  1454. Unit *unit;
  1455. int x, y, dist;
  1456. {
  1457.     Task *task;
  1458.  
  1459.     if (!tasked_unit_valid(unit, "move"))
  1460.       return;
  1461.     clear_task_agenda(unit->plan);
  1462.     task = create_movenear_task(x, y, dist);
  1463.     unit->plan->tasks = task;
  1464.     be_active(unit);
  1465.     update_unit_display(unit->side, unit, FALSE);
  1466. }
  1467.  
  1468. void
  1469. push_movenear_task(unit, x, y, dist)
  1470. Unit *unit;
  1471. int x, y, dist;
  1472. {
  1473.     Task *task;
  1474.  
  1475.     if (!tasked_unit_valid(unit, "move"))
  1476.       return;
  1477.     task = create_movenear_task(x, y, dist);
  1478.     push_task(unit, task);
  1479.     be_active(unit);
  1480.     update_unit_display(unit->side, unit, FALSE);
  1481. }
  1482.  
  1483. /* Create a task to move in a given direction for a given distance. */
  1484.  
  1485. Task *
  1486. create_movedir_task(dir, n)
  1487. int dir, n;
  1488. {
  1489.     Task *task = create_task(TASK_MOVEDIR);
  1490.  
  1491.     task->args[0] = dir;
  1492.     task->args[1] = n;
  1493.     return task;
  1494. }
  1495.  
  1496. /* Fill in the given unit with direction-moving orders. */
  1497.  
  1498. void
  1499. set_movedir_task(unit, dir, n)
  1500. Unit *unit;
  1501. int dir, n;
  1502. {
  1503.     clear_task_agenda(unit->plan);
  1504.     unit->plan->tasks = create_movedir_task(dir, n);
  1505.     be_active(unit);
  1506.     update_unit_display(unit->side, unit, FALSE);
  1507. }
  1508.  
  1509. /* This routine sets up a task to build a unit of the given type. */
  1510.  
  1511. Task *
  1512. create_build_task(u2, run)
  1513. int u2, run;
  1514. {
  1515.     Task *task = create_task(TASK_BUILD);
  1516.  
  1517.     task->args[0] = u2;
  1518.     task->args[3] = run;
  1519.     return task;
  1520. }
  1521.  
  1522. void
  1523. push_build_task(unit, u2, run)
  1524. Unit *unit;
  1525. int u2, run;
  1526. {
  1527.     Task *task;
  1528.  
  1529.     if (!tasked_unit_valid(unit, "build"))
  1530.       return;
  1531.     task = create_build_task(u2, run);
  1532.     push_task(unit, task);
  1533.     be_active(unit);
  1534.     update_unit_display(unit->side, unit, FALSE);
  1535. }
  1536.  
  1537. /* This routine sets up a task to research a unit of the given type. */
  1538.  
  1539. Task *
  1540. create_research_task(u2, n)
  1541. int u2, n;
  1542. {
  1543.     Task *task = create_task(TASK_RESEARCH);
  1544.  
  1545.     task->args[0] = u2;
  1546.     task->args[1] = n;
  1547.     return task;
  1548. }
  1549.  
  1550. void
  1551. push_research_task(unit, u2, n)
  1552. Unit *unit;
  1553. int u2, n;
  1554. {
  1555.     Task *task;
  1556.  
  1557.     if (!tasked_unit_valid(unit, "research"))
  1558.       return;
  1559.     task = create_research_task(u2, n);
  1560.     push_task(unit, task);
  1561.     be_active(unit);
  1562.     update_unit_display(unit->side, unit, FALSE);
  1563. }
  1564.  
  1565. void
  1566. set_hit_task(unit, x, y)
  1567. Unit *unit;
  1568. int x, y;
  1569. {
  1570.     Task *task = create_task(TASK_HIT_UNIT);
  1571.  
  1572.     task->args[0] = x;  task->args[1] = y;
  1573.     task->args[2] = NONUTYPE;  task->args[3] = -1;
  1574.     clear_task_agenda(unit->plan);
  1575.     unit->plan->tasks = task;
  1576.     update_unit_display(unit->side, unit, FALSE);
  1577. }
  1578.  
  1579. void
  1580. push_specific_hit_task(unit, x, y, u, s)
  1581. Unit *unit;
  1582. int x, y, u, s;
  1583. {
  1584.     Task *task = create_task(TASK_HIT_UNIT);
  1585.  
  1586.     task->args[0] = x;  task->args[1] = y;
  1587.     task->args[2] = u;  task->args[3] = s;
  1588.     push_task(unit, task);
  1589.     be_active(unit);
  1590.     update_unit_display(unit->side, unit, FALSE);
  1591. }
  1592.  
  1593. void
  1594. set_specific_hit_task(unit, x, y, u, s)
  1595. Unit *unit;
  1596. int x, y, u, s;
  1597. {
  1598.     Task *task = create_task(TASK_HIT_UNIT);
  1599.  
  1600.     task->args[0] = x;  task->args[1] = y;
  1601.     task->args[2] = u;  task->args[3] = s;
  1602.     clear_task_agenda(unit->plan);
  1603.     unit->plan->tasks = task;
  1604.     update_unit_display(unit->side, unit, FALSE);
  1605. }
  1606.  
  1607. void
  1608. push_hit_task(unit, x, y)
  1609. Unit *unit;
  1610. int x, y;
  1611. {
  1612.     Task *task = create_task(TASK_HIT_UNIT);
  1613.  
  1614.     task->args[0] = x;  task->args[1] = y;
  1615.     task->args[2] = NONUTYPE;  task->args[3] = -1 /* allsidesmask */;
  1616.     push_task(unit, task);
  1617.     be_active(unit);
  1618.     update_unit_display(unit->side, unit, FALSE);
  1619. }
  1620.  
  1621. void
  1622. set_capture_task(unit, x, y)
  1623. Unit *unit;
  1624. int x, y;
  1625. {
  1626.     Task *task = create_task(TASK_CAPTURE_UNIT);
  1627.  
  1628.     task->args[0] = x;  task->args[1] = y;
  1629.     clear_task_agenda(unit->plan);
  1630.     unit->plan->tasks = task;
  1631.     update_unit_display(unit->side, unit, FALSE);
  1632. }
  1633.  
  1634. void
  1635. push_capture_task(unit, x, y)
  1636. Unit *unit;
  1637. int x, y;
  1638. {
  1639.     Task *task = create_task(TASK_CAPTURE_UNIT);
  1640.  
  1641.     task->args[0] = x;  task->args[1] = y;
  1642.     push_task(unit, task);
  1643.     be_active(unit);
  1644.     update_unit_display(unit->side, unit, FALSE);
  1645. }
  1646.  
  1647. void
  1648. set_resupply_task(unit)
  1649. Unit *unit;
  1650. {
  1651.     Task *task;
  1652.  
  1653.     if (!tasked_unit_valid(unit, "resupply"))
  1654.       return;
  1655.     clear_task_agenda(unit->plan);
  1656.     task = create_task(TASK_RESUPPLY);
  1657.     unit->plan->tasks = task;
  1658.     be_active(unit);
  1659.     update_unit_display(unit->side, unit, FALSE);
  1660. }
  1661.  
  1662. Task *
  1663. create_occupy_task(transport)
  1664. Unit *transport;
  1665. {
  1666.     Task *task = create_task(TASK_OCCUPY);
  1667.  
  1668.     task->args[0] = transport->id;
  1669.     /* add a waiting period also? */
  1670.     return task;
  1671. }
  1672.  
  1673. void
  1674. push_occupy_task(unit, transp)
  1675. Unit *unit, *transp;
  1676. {
  1677.     Task *task;
  1678.  
  1679.     if (!tasked_unit_valid(unit, "occupy"))
  1680.       return;
  1681.     task = create_occupy_task(transp);
  1682.     push_task(unit, task);
  1683.     be_active(unit);
  1684.     update_unit_display(unit->side, unit, FALSE);
  1685. }
  1686.  
  1687. Task *
  1688. create_pickup_task(occ)
  1689. Unit *occ;
  1690. {
  1691.     Task *task = create_task(TASK_PICKUP);
  1692.  
  1693.     task->args[0] = occ->id;
  1694.     /* add a waiting period also? */
  1695.     return task;
  1696. }
  1697.  
  1698. void
  1699. push_pickup_task(unit, occ)
  1700. Unit *unit, *occ;
  1701. {
  1702.     Task *task;
  1703.  
  1704.     if (!tasked_unit_valid(unit, "pickup"))
  1705.       return;
  1706.     task = create_pickup_task(occ);
  1707.     push_task(unit, task);
  1708.     be_active(unit);
  1709.     update_unit_display(unit->side, unit, FALSE);
  1710. }
  1711.  
  1712. int
  1713. tasked_unit_valid(unit, tasktypename)
  1714. Unit *unit;
  1715. char *tasktypename;
  1716. {
  1717.     if (!in_play(unit) || unit->plan == NULL) {
  1718.     run_warning("Trying to do %s task with bad %s",
  1719.             tasktypename, unit_desig(unit));
  1720.     return FALSE;
  1721.     }
  1722.     return TRUE;
  1723. }
  1724.  
  1725. /* Describe a task succinctly - use for debugging only. */
  1726.  
  1727. char *
  1728. task_desig(task)
  1729. Task *task;
  1730. {
  1731.     int i, slen;
  1732.     char *argtypes;
  1733.  
  1734.     if (taskbuf == NULL)
  1735.       taskbuf = xmalloc(BUFSIZE);
  1736.     if (task) {
  1737.     sprintf(taskbuf, "{%s", taskdefns[task->type].name);
  1738.     argtypes = taskdefns[task->type].argtypes;
  1739.     slen = strlen(argtypes);
  1740.     for (i = 0; i < slen; ++i) {
  1741.         tprintf(taskbuf, "%c%d", (i == 0 ? ' ' : ','), task->args[i]);
  1742.     }
  1743.     tprintf(taskbuf, " x %d", task->execnum);
  1744.     if (task->retrynum > 0) {
  1745.         tprintf(taskbuf, " fail %d", task->retrynum);
  1746.     }
  1747.     strcat(taskbuf, "}");
  1748.     } else {
  1749.     sprintf(taskbuf, "no task");
  1750.     }
  1751.     return taskbuf;
  1752. }
  1753.  
  1754.